#include "zoneNEWER.h"
#include "paletteNEWER.h"
#include "decompress.h"
#include "plcsystem.h"
#include <stdio.h>


#define palid_GHZ 4

#define plcid_GHZ 4
#define plcid_GHZ2 5
/*
; ---------------------------------------------------------------------------
; Pattern load cue IDs
; ---------------------------------------------------------------------------
plcid_Main:		equ (ptr_PLC_Main-ArtLoadCues)/2	; 0
plcid_Main2:		equ (ptr_PLC_Main2-ArtLoadCues)/2	; 1
plcid_Explode:		equ (ptr_PLC_Explode-ArtLoadCues)/2	; 2
plcid_GameOver:		equ (ptr_PLC_GameOver-ArtLoadCues)/2	; 3
plcid_GHZ:		equ (ptr_PLC_GHZ-ArtLoadCues)/2		; 4
plcid_GHZ2:		equ (ptr_PLC_GHZ2-ArtLoadCues)/2	; 5
plcid_LZ:		equ (ptr_PLC_LZ-ArtLoadCues)/2		; 6
plcid_LZ2:		equ (ptr_PLC_LZ2-ArtLoadCues)/2		; 7
plcid_MZ:		equ (ptr_PLC_MZ-ArtLoadCues)/2		; 8
plcid_MZ2:		equ (ptr_PLC_MZ2-ArtLoadCues)/2		; 9
plcid_SLZ:		equ (ptr_PLC_SLZ-ArtLoadCues)/2		; $A
plcid_SLZ2:		equ (ptr_PLC_SLZ2-ArtLoadCues)/2	; $B
plcid_SYZ:		equ (ptr_PLC_SYZ-ArtLoadCues)/2		; $C
plcid_SYZ2:		equ (ptr_PLC_SYZ2-ArtLoadCues)/2	; $D
plcid_SBZ:		equ (ptr_PLC_SBZ-ArtLoadCues)/2		; $E
plcid_SBZ2:		equ (ptr_PLC_SBZ2-ArtLoadCues)/2	; $F
plcid_TitleCard:	equ (ptr_PLC_TitleCard-ArtLoadCues)/2	; $10
plcid_Boss:		equ (ptr_PLC_Boss-ArtLoadCues)/2	; $11
plcid_Signpost:		equ (ptr_PLC_Signpost-ArtLoadCues)/2	; $12
plcid_Warp:		equ (ptr_PLC_Warp-ArtLoadCues)/2	; $13
plcid_SpecialStage:	equ (ptr_PLC_SpecialStage-ArtLoadCues)/2 ; $14
plcid_GHZAnimals:	equ (ptr_PLC_GHZAnimals-ArtLoadCues)/2	; $15
plcid_LZAnimals:	equ (ptr_PLC_LZAnimals-ArtLoadCues)/2	; $16
plcid_MZAnimals:	equ (ptr_PLC_MZAnimals-ArtLoadCues)/2	; $17
plcid_SLZAnimals:	equ (ptr_PLC_SLZAnimals-ArtLoadCues)/2	; $18
plcid_SYZAnimals:	equ (ptr_PLC_SYZAnimals-ArtLoadCues)/2	; $19
plcid_SBZAnimals:	equ (ptr_PLC_SBZAnimals-ArtLoadCues)/2	; $1A
plcid_SSResult:		equ (ptr_PLC_SSResult-ArtLoadCues)/2	; $1B
plcid_Ending:		equ (ptr_PLC_Ending-ArtLoadCues)/2	; $1C
plcid_TryAgain:		equ (ptr_PLC_TryAgain-ArtLoadCues)/2	; $1D
plcid_EggmanSBZ2:	equ (ptr_PLC_EggmanSBZ2-ArtLoadCues)/2	; $1E
plcid_FZBoss:		equ (ptr_PLC_FZBoss-ArtLoadCues)/2	; $1F
*/
word v_lastlamp;

byte v_256x256[0xA400];  //0xA400 bytes                 
byte v_16x16[0x1800];     //0x1800 bytes

byte v_lvllayout[0x400*2]; //(0x400 * 2) bytes

extern byte v_zone;
extern byte v_act;
extern word v_debuguse;
extern word v_limitleft2;
extern word v_limitright2;
extern byte f_timecount;
extern long v_screenposx;

extern byte Blk16_GHZ[];

extern byte Blk256_GHZ[];

extern byte Level_GHZ1[];
byte Level_GHZ1null[] = { 0, 0, 0, 0 };
extern byte Level_GHZ2[];
byte Level_GHZ2null[] = { 0, 0, 0, 0 };
extern byte Level_GHZ3[];
extern byte Level_GHZbg[];
byte Level_GHZ3null[] = { 0, 0, 0, 0 };

#define LONGTOWORD LEFTRADIXLONG
#define LEFTRADIXLONG(val) ((val & 0xFFFF0000) >> 16) 

//level headers are an array of structs so they can easily be defined like in the assembly
#define lhead(plc1,lvlgfx,plc2,sixteen,twofivesix,music,pal) { plc1, lvlgfx, plc2, sixteen, twofivesix, 0, music, pal, pal }
struct levelHeader
{
    byte plc1;
    union { byte *lvlgfx; long lvlgfxAddr; };
    byte plc2;
    union { byte *sixteen; long sixteenAddr; };
    union { byte *twofivesix; long twofivesixAddr;};
    byte zero;
    byte musicUnused;
    byte palUnused;
    byte pal;
};
levelHeader LevelHeaders[] = { 
    lhead(plcid_GHZ, /*Nem_GHZ_2nd*/0, plcid_GHZ2, Blk16_GHZ, Blk256_GHZ, /*bgm_GHZ*/0, palid_GHZ) 
};

//level indexes are not relative pointers like in the ROM, these point directly to the binary level data
//  --binary data for individual levels generated by objcopy is not necessarily linked/stored contiguously  
byte *Level_Index[] = { 
    Level_GHZ1, Level_GHZbg, Level_GHZ1null,
    Level_GHZ2, Level_GHZbg, Level_GHZ2null, 
    Level_GHZ3, Level_GHZbg, Level_GHZ3null }; 
        

void LevelDataLoad()
{
    //moveq	#0,d0
    //move.b	(v_zone).w,d0
    byte zone = v_zone;

    //lsl.w	#4,d0
    //word zoneHeadersOffset = zone * 16;  //sizeof(levelHeader); 

    //lea	(LevelHeaders).l,a2
    //byte *LevelHeadersPtr = (byte*)LevelHeaders;
	
    //lea	(a2,d0.w),a2
    //byte *curZoneHeaders = (byte*)&LevelHeadersPtr[zoneHeadersOffset];
    levelHeader *curZoneHeader = &LevelHeaders[zone];

    //move.l	a2,-(sp)
    //byte *startZoneHeaders = curZoneHeaders;

    //addq.l	#4,a2
    //curZoneHeaders++; //+= 4;    //skip past level graphics entry
    //curZoneHeaders = (curZoneHeaders+6);

    //movea.l	(a2)+,a0
    //byte *eniData = (byte*)*((long*)curZoneHeaders++);
    byte *eniData = curZoneHeader->sixteen;

    //lea	(v_16x16).w,a1	; RAM address for 16x16 mappings
    byte *v_16x16Ptr = (byte*)v_16x16;	

    //move.w	#0,d0
    //bsr.w	EniDec
    EniDec(eniData, v_16x16Ptr);

    //movea.l	(a2)+,a0
    //byte *kosData = (byte*)*((long*)curZoneHeaders++);
    byte *kosData = curZoneHeader->twofivesix;    

    //lea	(v_256x256).l,a1 ; RAM address for 256x256 mappings
    byte *v_256x256Ptr = (byte*)v_256x256;	

    //bsr.w	KosDec
    KosDec(kosData, v_256x256Ptr, true);
    
    //bsr.w	LevelLayoutLoad
    LevelLayoutLoad();

    //move.w	(a2)+,d0
    //word musicUnused  = *((word*)curZoneHeaders);
    
    //move.w	(a2),d0
    //word palFull = *((word*)(curZoneHeaders)+1);
    word palFull = curZoneHeader->pal;

    //andi.w	#$FF,d0
    word pal =  palFull & 0xFF;

    //cmpi.w	#(id_LZ<<8)+3,(v_zone).w ; is level SBZ3 (LZ4) ?
    //bne.s	@notSBZ3	; if not, branch
    //moveq	#palid_SBZ3,d0	; use SB3 palette
    //@notSBZ3:
    //cmpi.w	#(id_SBZ<<8)+1,(v_zone).w ; is level SBZ2?
    //beq.s	@isSBZorFZ	; if yes, branch
    //cmpi.w	#(id_SBZ<<8)+2,(v_zone).w ; is level FZ?
    //bne.s	@normalpal	; if not, branch
    //@isSBZorFZ:
    //moveq	#palid_SBZ2,d0	; use SBZ2/FZ palette
    //@normalpal:
    
    //bsr.w	PalLoad1	; load palette (based on d0)
    PalLoad1(pal);

    //NOW we can load patterns for level objects...
    //movea.l	(sp)+,a2
    //curZoneHeaders = startZoneHeaders;

    //addq.w	#4,a2		; read number for 2nd PLC
    //curZoneHeaders = (long*)(((byte*)(curZoneHeaders))+5);

    //moveq	#0,d0
    //move.b	(a2),d0
    //byte objPLCid = *((byte*)(curZoneHeaders));
    byte objPLCid = curZoneHeader->plc2;

    //beq.s	@skipPLC	; if 2nd PLC is 0 (i.e. the ending sequence), branch
    if (objPLCid != 0)
    {
        //bsr.w	AddPLC		; load pattern load cues
        AddPLC(objPLCid);
    }
    //@skipPLC:
    //rts	
   
}

inline void LevelLayoutClear()
{
    //clear level layout RAM
    long *v_lvllayoutClr = (long*)v_lvllayout;
    word layoutSize = 0x1FF;
    long clearValue = 0;

    for (int lp = 0; lp <= layoutSize; lp++)
        v_lvllayoutClr[lp] = clearValue;
}

void LevelLayoutLoad()
{
    LevelLayoutClear();
    
    byte *loadDestFG = v_lvllayout;
    word layer = 0;
    LevelLayoutLoad2(layer, loadDestFG);    

    byte *loadDestBG = v_lvllayout + 0x40;
    layer = 1;                                  //this is 2 in ROM as it defines the offset in bytes from in the level_index table for the current level (i.e FG, BG, or NULL), which are WORD relative addresses
    LevelLayoutLoad2(layer, loadDestBG);

}

void LevelLayoutLoad2(word layerSrc, byte *loadDest)   
{
//LevelLayoutLoad2:			; XREF: LevelLayoutLoad
    //move.w	(v_zone).w,d0
    word zone = (v_zone<<8) + v_act; 

    /*========= THIS CODE SECTION IN THE ASSEMBLY INVOLVES RELATIVE ADDRESSING ========*/
    //lsl.b	#6,d0    
    //lsr.w	#5,d0    *2...
    //move.w	d0,d2    d2 = zone*2
    //add.w	d0,d0    d0 = zone*2+zone*2 = zone *4
    //add.w	d2,d0    d0 = zone*6
    //add.w	d1,d0    d0 = zone*6 + layerSrc
    //word LevelIndexNum = (zone * 6) + layerSrc;     we could use the equivalent c code for these calculations 
    word LevelIndexNum = (zone * 3) + layerSrc;  //   however the value of 6 implies (3*sizeof(word))- 3 `WORD` relative addresses for a level index...
                                                 //   Level_Index have been converted to pointers-which are absolute addresses
						 //   furthermore, no extra 'scaling' needs to be done when grabbing from a pointer array
    //lea	(Level_Index).l,a1               
    //word *Level_IndexPtr = Level_Index;	            //because level indexes no longer a list of word values,
    byte **Level_IndexPtr = Level_Index;                    //it is changed to a list of pointers to byte data

    //move.w	(a1,d0.w),d0                                // because relative addresses have been converted to absolute
    //word layoutAddress = Level_IndexPtr[LevelIndexNum];   // there is no need to do the extra math involved
    //lea	(a1,d0.w),a1                                // when adding the base address to the offset...
    //byte *Level_LayoutPtr = Level_IndexPtr[layoutAddress];// instead of this
    byte *Level_LayoutPtr = Level_IndexPtr[LevelIndexNum];  // the full address can be grabbed directly
    /*=================================================================================*/

    //moveq	#0,d1
    byte width = 0;

    //move.w	d1,d2
    byte height = 0;
    
    //move.b	(a1)+,d1	; load level width (in tiles)
    width = *(Level_LayoutPtr++);

    //move.b	(a1)+,d2	; load level height (in	tiles)
    height = *(Level_LayoutPtr++);

    //LevLoad_NumRows:
    for (signed short curRow = height; curRow >= 0; curRow--)
    {
        //move.w	d1,d0
        signed short curColumn = width;
    
        //movea.l	a3,a0
        byte *loadDestRowPtr = loadDest;
        
        //LevLoad_Row:
        for (; curColumn >= 0; curColumn--)
        {    
	    //move.b	(a1)+,(a0)+
            *(loadDestRowPtr++) = *(Level_LayoutPtr++);
        }
	//dbf	d0,LevLoad_Row	; load 1 row
	
        //lea	$80(a3),a3	; do next row
        loadDest += 128;                         //64*2 bytes per row for each layer (FG & BG) in level layout ram
     }
     //dbf	d2,LevLoad_NumRows ; repeat for	number of rows
//rts	
} //; End of function LevelLayoutLoad2

//==============================================================
//SignpostArtLoad:			; XREF: GM_Level
void SignpostArtLoad()
{
    //tst.w	(v_debuguse).w	; is debug mode	being used?
    //bne.w	@exit		; if yes, branch
    if (v_debuguse == 0)
    {
        //cmpi.b	#2,(v_act).w	; is act number 02 (act 3)?
        //beq.s	@exit		; if yes, branch
        if (v_act != 2)
        {
	    //move.w	(v_screenposx).w,d0
            word screenposx = LONGTOWORD(v_screenposx);

	    //move.w	(v_limitright2).w,d1
            //subi.w	#$100,d1
            word limitright = v_limitright2 - 0x100;

	    //cmp.w	d1,d0		; has Sonic reached the	edge of	the level?
            //blt.s	@exit		; if not, branch
            if (screenposx >= limitright)
            {
                //tst.b	(f_timecount).w
                //beq.s	@exit
                if (f_timecount != 0)
		{
		    //cmp.w	(v_limitleft2).w,d1
                    //beq.s	@exit
                    if (v_limitleft2 != limitright)
                    {
		        //move.w	d1,(v_limitleft2).w ; move left boundary to current screen position
                        v_limitleft2 = limitright;

                        #define plcid_Signpost 18
		        //moveq	#plcid_Signpost,d0
		        //bra.w	NewPLC		; load signpost	patterns
                        NewPLC(plcid_Signpost);
                    }
                    
                    //@exit:
		    //rts	
                }
            }
        }
    }
}   //; End of function SignpostArtLoad
